home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / base / netkit-b.07a / netkit-b / NetKit-B-0.07A / ftp / glob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-20  |  11.5 KB  |  694 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. /*
  35.  * From: @(#)glob.c    5.9 (Berkeley) 2/25/91
  36.  */
  37. char glob_rcsid[] = 
  38.   "$Id: glob.c,v 1.4 1996/07/20 20:43:13 dholland Exp $";
  39.  
  40. /*
  41.  * C-shell glob for random programs.
  42.  */
  43.  
  44. #include <sys/param.h>
  45. #include <sys/stat.h>
  46. #include <dirent.h>
  47.  
  48. #include <pwd.h>
  49. #include <errno.h>
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53.  
  54. #include "ftp_var.h"  /* for protos only */
  55.  
  56. #define    QUOTE 0200
  57. #define    TRIM 0177
  58. #define    eq(a,b)        (strcmp(a, b)==0)
  59. #define    GAVSIZ        (ARG_MAX/6)
  60. #define    isdir(d)    ((d.st_mode & S_IFMT) == S_IFDIR)
  61.  
  62. static    char **gargv;        /* Pointer to the (stack) arglist */
  63. static    int gargc;        /* Number args in gargv */
  64. static    int gnleft;
  65. static    short gflag;
  66. static    int tglob();
  67. char    **ftpglob();
  68. char    *globerr;
  69. char    *home;
  70. extern    int errno;
  71. static    char *strspl(), *strend();
  72. char    **copyblk();
  73.  
  74. static void acollect(), addpath(), collect(), expand(), Gcat();
  75. static void ginit(), matchdir(), rscan(), sort();
  76. static int amatch(), execbrc(), match();
  77.  
  78. static int gethdir(char *home);
  79. static int letter(char c);
  80. static int digit(char c);
  81. static int any(int c, char *s);
  82.  
  83. static    int globcnt;
  84.  
  85. static char    *globchars = "`{[*?";
  86.  
  87. static    char *gpath, *gpathp, *lastgpathp;
  88. static    int globbed;
  89. static    char *entp;
  90. static    char **sortbas;
  91.  
  92. char **
  93. ftpglob(v)
  94.     register char *v;
  95. {
  96.     char agpath[BUFSIZ];
  97.     char *agargv[GAVSIZ];
  98.     char *vv[2];
  99.     vv[0] = v;
  100.     vv[1] = 0;
  101.     gflag = 0;
  102.     rscan(vv, tglob);
  103.     if (gflag == 0)
  104.         return (copyblk(vv));
  105.  
  106.     globerr = 0;
  107.     gpath = agpath; gpathp = gpath; *gpathp = 0;
  108.     lastgpathp = &gpath[sizeof agpath - 2];
  109.     ginit(agargv); globcnt = 0;
  110.     collect(v);
  111.     if (globcnt == 0 && (gflag&1)) {
  112.         blkfree(gargv), gargv = 0;
  113.         return (0);
  114.     } else
  115.         return (gargv = copyblk(gargv));
  116. }
  117.  
  118. static void
  119. ginit(agargv)
  120.     char **agargv;
  121. {
  122.  
  123.     agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0;
  124.     gnleft = ARG_MAX - 4;
  125. }
  126.  
  127. static void
  128. collect(as)
  129.     register char *as;
  130. {
  131.     if (eq(as, "{") || eq(as, "{}")) {
  132.         Gcat(as, "");
  133.         sort();
  134.     } else
  135.         acollect(as);
  136. }
  137.  
  138. static void
  139. acollect(as)
  140.     register char *as;
  141. {
  142.     register int ogargc = gargc;
  143.  
  144.     gpathp = gpath; *gpathp = 0; globbed = 0;
  145.     expand(as);
  146.     if (gargc != ogargc)
  147.         sort();
  148. }
  149.  
  150. static void
  151. sort()
  152. {
  153.     register char **p1, **p2, *c;
  154.     char **Gvp = &gargv[gargc];
  155.  
  156.     p1 = sortbas;
  157.     while (p1 < Gvp-1) {
  158.         p2 = p1;
  159.         while (++p2 < Gvp)
  160.             if (strcmp(*p1, *p2) > 0)
  161.                 c = *p1, *p1 = *p2, *p2 = c;
  162.         p1++;
  163.     }
  164.     sortbas = Gvp;
  165. }
  166.  
  167. static void
  168. expand(as)
  169.     char *as;
  170. {
  171.     register char *cs;
  172.     register char *sgpathp, *oldcs;
  173.     struct stat stb;
  174.  
  175.     sgpathp = gpathp;
  176.     cs = as;
  177.     if (*cs == '~' && gpathp == gpath) {
  178.         addpath('~');
  179.         for (cs++; letter(*cs) || digit(*cs) || *cs == '-';)
  180.             addpath(*cs++);
  181.         if (!*cs || *cs == '/') {
  182.             if (gpathp != gpath + 1) {
  183.                 *gpathp = 0;
  184.                 if (gethdir(gpath + 1))
  185.                     globerr = "Unknown user name after ~";
  186.                 (void) strcpy(gpath, gpath + 1);
  187.             } else
  188.                 (void) strcpy(gpath, home);
  189.             gpathp = strend(gpath);
  190.         }
  191.     }
  192.     while (!any(*cs, globchars)) {
  193.         if (*cs == 0) {
  194.             if (!globbed)
  195.                 Gcat(gpath, "");
  196.             else if (stat(gpath, &stb) >= 0) {
  197.                 Gcat(gpath, "");
  198.                 globcnt++;
  199.             }
  200.             goto endit;
  201.         }
  202.         addpath(*cs++);
  203.     }
  204.     oldcs = cs;
  205.     while (cs > as && *cs != '/')
  206.         cs--, gpathp--;
  207.     if (*cs == '/')
  208.         cs++, gpathp++;
  209.     *gpathp = 0;
  210.     if (*oldcs == '{') {
  211.         (void) execbrc(cs, ((char *)0));
  212.         return;
  213.     }
  214.     matchdir(cs);
  215. endit:
  216.     gpathp = sgpathp;
  217.     *gpathp = 0;
  218. }
  219.  
  220. static void
  221. matchdir(pattern)
  222.     char *pattern;
  223. {
  224.     struct stat stb;
  225.     register struct dirent *dp;
  226.     DIR *dirp;
  227.  
  228. #ifdef    __linux__
  229.     if (gpath == NULL || *gpath == '\0')
  230.         gpath = "./";
  231. #endif
  232.     dirp = opendir(gpath);
  233.     if (dirp == NULL) {
  234.         if (globbed)
  235.             return;
  236.         goto patherr2;
  237.     }
  238.     if (fstat(dirfd(dirp), &stb) < 0)
  239.         goto patherr1;
  240.     if (!isdir(stb)) {
  241.         errno = ENOTDIR;
  242.         goto patherr1;
  243.     }
  244.     while ((dp = readdir(dirp)) != NULL) {
  245.         if (dp->d_ino == 0)
  246.             continue;
  247.         if (match(dp->d_name, pattern)) {
  248.             Gcat(gpath, dp->d_name);
  249.             globcnt++;
  250.         }
  251.     }
  252.     closedir(dirp);
  253.     return;
  254.  
  255. patherr1:
  256.     closedir(dirp);
  257. patherr2:
  258.     globerr = "Bad directory components";
  259. }
  260.  
  261. static int
  262. execbrc(p, s)
  263.     char *p, *s;
  264. {
  265.     char restbuf[BUFSIZ + 2];
  266.     register char *pe, *pm, *pl;
  267.     int brclev = 0;
  268.     char *lm, savec, *sgpathp;
  269.  
  270.     for (lm = restbuf; *p != '{'; *lm++ = *p++)
  271.         continue;
  272.     for (pe = ++p; *pe; pe++)
  273.     switch (*pe) {
  274.  
  275.     case '{':
  276.         brclev++;
  277.         continue;
  278.  
  279.     case '}':
  280.         if (brclev == 0)
  281.             goto pend;
  282.         brclev--;
  283.         continue;
  284.  
  285.     case '[':
  286.         for (pe++; *pe && *pe != ']'; pe++)
  287.             continue;
  288.         continue;
  289.     }
  290. pend:
  291.     brclev = 0;
  292.     for (pl = pm = p; pm <= pe; pm++)
  293.     switch (*pm & (QUOTE|TRIM)) {
  294.  
  295.     case '{':
  296.         brclev++;
  297.         continue;
  298.  
  299.     case '}':
  300.         if (brclev) {
  301.             brclev--;
  302.             continue;
  303.         }
  304.         goto doit;
  305.  
  306.     case ','|QUOTE:
  307.     case ',':
  308.         if (brclev)
  309.             continue;
  310. doit:
  311.         savec = *pm;
  312.         *pm = 0;
  313.         (void) strcpy(lm, pl);
  314.         (void) strcat(restbuf, pe + 1);
  315.         *pm = savec;
  316.         if (s == 0) {
  317.             sgpathp = gpathp;
  318.             expand(restbuf);
  319.             gpathp = sgpathp;
  320.             *gpathp = 0;
  321.         } else if (amatch(s, restbuf))
  322.             return (1);
  323.         sort();
  324.         pl = pm + 1;
  325.         if (brclev)
  326.             return (0);
  327.         continue;
  328.  
  329.     case '[':
  330.         for (pm++; *pm && *pm != ']'; pm++)
  331.             continue;
  332.         if (!*pm)
  333.             pm--;
  334.         continue;
  335.     }
  336.     if (brclev)
  337.         goto doit;
  338.     return (0);
  339. }
  340.  
  341. static int
  342. match(s, p)
  343.     char *s, *p;
  344. {
  345.     register int c;
  346.     register char *sentp;
  347.     char sglobbed = globbed;
  348.  
  349.     if (*s == '.' && *p != '.')
  350.         return (0);
  351.     sentp = entp;
  352.     entp = s;
  353.     c = amatch(s, p);
  354.     entp = sentp;
  355.     globbed = sglobbed;
  356.     return (c);
  357. }
  358.  
  359. static int
  360. amatch(s, p)
  361.     register char *s, *p;
  362. {
  363.     register int scc;
  364.     int ok, lc;
  365.     char *sgpathp;
  366.     struct stat stb;
  367.     int c, cc;
  368.  
  369.     globbed = 1;
  370.     for (;;) {
  371.         scc = *s++ & TRIM;
  372.         switch (c = *p++) {
  373.  
  374.         case '{':
  375.             return (execbrc(p - 1, s - 1));
  376.  
  377.         case '[':
  378.             ok = 0;
  379.             lc = 077777;
  380.             while ((cc = *p++) != 0) {
  381.                 if (cc == ']') {
  382.                     if (ok)
  383.                         break;
  384.                     return (0);
  385.                 }
  386.                 if (cc == '-') {
  387.                     if (lc <= scc && scc <= *p++)
  388.                         ok++;
  389.                 } else
  390.                     if (scc == (lc = cc))
  391.                         ok++;
  392.             }
  393.             if (cc == 0)
  394.                 if (ok)
  395.                     p--;
  396.                 else
  397.                     return 0;
  398.             continue;
  399.  
  400.         case '*':
  401.             if (!*p)
  402.                 return (1);
  403.             if (*p == '/') {
  404.                 p++;
  405.                 goto slash;
  406.             }
  407.             s--;
  408.             do {
  409.                 if (amatch(s, p))
  410.                     return (1);
  411.             } while (*s++);
  412.             return (0);
  413.  
  414.         case 0:
  415.             return (scc == 0);
  416.  
  417.         default:
  418.             if (c != scc)
  419.                 return (0);
  420.             continue;
  421.  
  422.         case '?':
  423.             if (scc == 0)
  424.                 return (0);
  425.             continue;
  426.  
  427.         case '/':
  428.             if (scc)
  429.                 return (0);
  430. slash:
  431.             s = entp;
  432.             sgpathp = gpathp;
  433.             while (*s)
  434.                 addpath(*s++);
  435.             addpath('/');
  436.             if (stat(gpath, &stb) == 0 && isdir(stb))
  437.                 if (*p == 0) {
  438.                     Gcat(gpath, "");
  439.                     globcnt++;
  440.                 } else
  441.                     expand(p);
  442.             gpathp = sgpathp;
  443.             *gpathp = 0;
  444.             return (0);
  445.         }
  446.     }
  447. }
  448.  
  449. static int
  450. Gmatch(s, p)
  451.     register char *s, *p;
  452. {
  453.     register int scc;
  454.     int ok, lc;
  455.     int c, cc;
  456.  
  457.     for (;;) {
  458.         scc = *s++ & TRIM;
  459.         switch (c = *p++) {
  460.  
  461.         case '[':
  462.             ok = 0;
  463.             lc = 077777;
  464.             while ((cc = *p++) != 0) {
  465.                 if (cc == ']') {
  466.                     if (ok)
  467.                         break;
  468.                     return (0);
  469.                 }
  470.                 if (cc == '-') {
  471.                     if (lc <= scc && scc <= *p++)
  472.                         ok++;
  473.                 } else
  474.                     if (scc == (lc = cc))
  475.                         ok++;
  476.             }
  477.             if (cc == 0)
  478.                 if (ok)
  479.                     p--;
  480.                 else
  481.                     return 0;
  482.             continue;
  483.  
  484.         case '*':
  485.             if (!*p)
  486.                 return (1);
  487.             for (s--; *s; s++)
  488.                 if (Gmatch(s, p))
  489.                     return (1);
  490.             return (0);
  491.  
  492.         case 0:
  493.             return (scc == 0);
  494.  
  495.         default:
  496.             if ((c & TRIM) != scc)
  497.                 return (0);
  498.             continue;
  499.  
  500.         case '?':
  501.             if (scc == 0)
  502.                 return (0);
  503.             continue;
  504.  
  505.         }
  506.     }
  507. }
  508.  
  509. static void
  510. Gcat(s1, s2)
  511.     register char *s1, *s2;
  512. {
  513.     register int len = strlen(s1) + strlen(s2) + 1;
  514.  
  515.     if (len >= gnleft || gargc >= GAVSIZ - 1)
  516.         globerr = "Arguments too long";
  517.     else {
  518.         gargc++;
  519.         gnleft -= len;
  520.         gargv[gargc] = 0;
  521.         gargv[gargc - 1] = strspl(s1, s2);
  522.     }
  523. }
  524.  
  525. static void
  526. addpath(c)
  527.     char c;
  528. {
  529.  
  530.     if (gpathp >= lastgpathp)
  531.         globerr = "Pathname too long";
  532.     else {
  533.         *gpathp++ = c;
  534.         *gpathp = 0;
  535.     }
  536. }
  537.  
  538. static void
  539. rscan(t, f)
  540.     register char **t;
  541.     int (*f)();
  542. {
  543.     register char *p, c;
  544.  
  545.     while ((p = *t++) != 0) {
  546.         if (f == tglob)
  547.             if (*p == '~')
  548.                 gflag |= 2;
  549.             else if (eq(p, "{") || eq(p, "{}"))
  550.                 continue;
  551.         while ((c = *p++) != 0)
  552.             (*f)(c);
  553.     }
  554. }
  555. /*
  556. static
  557. scan(t, f)
  558.     register char **t;
  559.     int (*f)();
  560. {
  561.     register char *p, c;
  562.  
  563.     while (p = *t++)
  564.         while (c = *p)
  565.             *p++ = (*f)(c);
  566. } */
  567.  
  568. static int
  569. tglob(c)
  570.     register char c;
  571. {
  572.  
  573.     if (any(c, globchars))
  574.         gflag |= c == '{' ? 2 : 1;
  575.     return (c);
  576. }
  577. /*
  578. static
  579. trim(c)
  580.     char c;
  581. {
  582.  
  583.     return (c & TRIM);
  584. } */
  585.  
  586. static int
  587. letter(char c)
  588. {
  589.  
  590.     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
  591. }
  592.  
  593. static int
  594. digit(char c)
  595. {
  596.  
  597.     return (c >= '0' && c <= '9');
  598. }
  599.  
  600. static int
  601. any(int c, char *s)
  602. {
  603.  
  604.     while (*s)
  605.         if (*s++ == c)
  606.             return(1);
  607.     return(0);
  608. }
  609.  
  610. int
  611. blklen(av)
  612.     register char **av;
  613. {
  614.     register int i = 0;
  615.  
  616.     while (*av++)
  617.         i++;
  618.     return (i);
  619. }
  620.  
  621. char **
  622. blkcpy(oav, bv)
  623.     char **oav;
  624.     register char **bv;
  625. {
  626.     register char **av = oav;
  627.  
  628.     while ((*av++ = *bv++) != 0)
  629.         continue;
  630.     return (oav);
  631. }
  632.  
  633. void
  634. blkfree(char **av0)
  635. {
  636.     register char **av = av0;
  637.  
  638.     while (*av)
  639.         free(*av++);
  640. }
  641.  
  642. static
  643. char *
  644. strspl(cp, dp)
  645.     register char *cp, *dp;
  646. {
  647.     register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
  648.  
  649.     if (ep == (char *)0)
  650.         fatal("Out of memory");
  651.     (void) strcpy(ep, cp);
  652.     (void) strcat(ep, dp);
  653.     return (ep);
  654. }
  655.  
  656. char **
  657. copyblk(v)
  658.     register char **v;
  659. {
  660.     register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
  661.                         sizeof(char **)));
  662.     if (nv == (char **)0)
  663.         fatal("Out of memory");
  664.  
  665.     return (blkcpy(nv, v));
  666. }
  667.  
  668. static
  669. char *
  670. strend(cp)
  671.     register char *cp;
  672. {
  673.  
  674.     while (*cp)
  675.         cp++;
  676.     return (cp);
  677. }
  678. /*
  679.  * Extract a home directory from the password file
  680.  * The argument points to a buffer where the name of the
  681.  * user whose home directory is sought is currently.
  682.  * We write the home directory of the user back there.
  683.  */
  684. static int
  685. gethdir(char *home)
  686. {
  687.     register struct passwd *pp = getpwnam(home);
  688.  
  689.     if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
  690.         return (1);
  691.     (void) strcpy(home, pp->pw_dir);
  692.     return (0);
  693. }
  694.